export interface MouseMoverProps {
  id?: string | [string, string]
  canScaleByMousewheel?: boolean
  defaultScale?: number
}

const changeElementTransform = (ele: HTMLElement, type: string, value: string) => {
  if (ele) {
    if (ele.style.transform) {
      const list = ele.style.transform.split(') ').map((item) => {
        return item.indexOf(')') === -1 ? item + ')' : item
      })
      const newList = list.filter((item) => item.indexOf(type) === -1)
      newList.push(`${type}(${value})`)
      ele.style.transform = newList.join(' ')
    } else {
      ele.style.transform = `${type}(${value})`
    }
  }
}

/* 元素跟随鼠标移动（模块化的）*/
class MouseMover {
  #grabEle: HTMLElement | null = null // 可抓住的元素
  #moveEle: HTMLElement | null = null // 被移动的元素
  #activate: boolean = false // 当前是否mousedown
  #x: number = 0 // mousedown时坐标
  #y: number = 0
  #offsetX: number = 0 // 当前的偏移量
  #offsetY: number = 0
  #lastOffsetX: number = 0 // 上一次的偏移量
  #lastOffsetY: number = 0
  #onMousedown: (arg0: MouseEvent) => void
  #onMousemove: (arg0: MouseEvent) => void
  #onMouseup: () => void
  #onMousewheel: (arg0: any) => void
  #canScaleByMousewheel: boolean = false
  #scale: number = 1
  constructor(props?: MouseMoverProps) {
    this.#onMousedown = (e) => this.onMousedown(e)
    this.#onMousemove = (e) => this.onMousemove(e)
    this.#onMouseup = () => this.onMouseup()
    this.#onMousewheel = (e) => this.onMousewheel(e)

    const { id, canScaleByMousewheel, defaultScale } = props || {}
    this.#canScaleByMousewheel = !!canScaleByMousewheel
    this.#scale = defaultScale || 1

    setTimeout(() => {
      id && this.init(id)
    }, 0)
  }
  init(id: string | [string, string]) {
    if (typeof id === 'string' && id) {
      this.#grabEle = this.#moveEle = document.getElementById(id)
    } else if (Array.isArray(id) && id.length > 0 && id.length <= 2) {
      this.#grabEle = document.getElementById(id[0])
      this.#moveEle = document.getElementById(id[1])
    } else {
      console.log('无效id格式')
      return
    }
    if (!this.#grabEle || !this.#moveEle) {
      console.log('元素无法找到', this.#grabEle, this.#moveEle)
      return
    }
    this.#grabEle.style.cursor = 'move'
    this.#grabEle.style.userSelect = 'none'
    document.addEventListener('mousemove', this.#onMousemove)
    document.addEventListener('mouseup', this.#onMouseup)
    this.#grabEle.addEventListener('mousedown', this.#onMousedown)
    if (this.#canScaleByMousewheel) {
      this.#grabEle.addEventListener('mousewheel', this.#onMousewheel)
    }
  }
  destroy() {
    document.removeEventListener('mousemove', this.#onMousemove)
    document.removeEventListener('mouseup', this.#onMouseup)
    this.#grabEle?.removeEventListener('mousedown', this.#onMousedown)
    if (this.#canScaleByMousewheel) {
      this.#grabEle?.addEventListener('mousewheel', this.#onMousewheel)
    }
  }
  onMousedown(e: MouseEvent) {
    this.#x = e.x
    this.#y = e.y
    this.#activate = true
  }
  onMousemove(e: MouseEvent) {
    if (this.#activate) {
      this.#offsetX = (e.x - this.#x) / this.#scale
      this.#offsetY = (e.y - this.#y) / this.#scale
      const x = this.#lastOffsetX + this.#offsetX
      const y = this.#lastOffsetY + this.#offsetY
      if (this.#moveEle) {
        changeElementTransform(this.#moveEle, 'translate', `${x}px, ${y}px`)
      }
    }
  }
  onMouseup() {
    if (this.#activate) {
      this.#lastOffsetX += this.#offsetX
      this.#lastOffsetY += this.#offsetY
      this.#activate = false
    }
  }
  onMousewheel(e: any) {
    if (!this.#moveEle) return
    if (e.wheelDelta > 0) {
      this.#scale *= 1.2
      this.#lastOffsetX /= 1.2
      this.#lastOffsetY /= 1.2
    } else {
      this.#scale = this.#scale / 1.2
      this.#lastOffsetX *= 1.2
      this.#lastOffsetY *= 1.2
    }
    changeElementTransform(this.#moveEle, 'scale', `${this.#scale}`)
    changeElementTransform(
      this.#moveEle,
      'translate',
      `${this.#lastOffsetX}px, ${this.#lastOffsetY}px`
    )
  }
}

export default MouseMover
